using System;
using System.Collections.Generic;
using System.Text;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using System.Diagnostics;

namespace MoEngine
{
    public class Graph2D
    {
        protected GraphCollection m_ChildrenGraphBelow = new GraphCollection();
        protected GraphCollection m_ChildrenGraphAbove = new GraphCollection();

        public virtual void UpdateAll(GameTime gameTime)
        {
			// TODO: let's do locking thing, locking detach here, if not locked detach immidiately
			DetachPendings();

            Update(gameTime);

            m_ChildrenGraphBelow.UpdateAll(gameTime);
            m_ChildrenGraphAbove.UpdateAll(gameTime);

			DetachPendings();
        }

        protected virtual void Update(GameTime gameTime) { }

        public virtual void RenderAll(Camera2D camera, SpriteBatch spriteBatch)
        {
            m_ChildrenGraphBelow.RenderAll(camera, spriteBatch);
            Render(camera, spriteBatch);
            m_ChildrenGraphAbove.RenderAll(camera, spriteBatch);
        }

        protected virtual void Render(Camera2D camera, SpriteBatch spriteBatch) { }

        private Graph2D m_Parent;

        public Graph2D Parent
        {
            get { return m_Parent; }
            set { m_Parent = value; }
        }

        private bool m_bAbove;

	    public bool IsAbove
	    {
		    get { return m_bAbove;}
		    set { m_bAbove = value;}
	    }

        private Vector2 m_RealLocation;

        public Vector2 RealLoction
        {
            get { return m_RealLocation; }
            set { m_RealLocation = value; }
        }

        public virtual void Attach(Graph2D child, bool bAbove)
        {
            Debug.Assert(child.Parent == null);

            child.Parent = this;
			child.IsAbove = bAbove;

            if (bAbove)
                m_ChildrenGraphAbove.Add(child);
            else
                m_ChildrenGraphBelow.Add(child);               
        }

        public virtual void Attach(Graph2D child)
        {
            Attach(child, true);
        }

		public LinkedList<Graph2D> m_PendingDetach = new LinkedList<Graph2D>();

		public void Detach(Graph2D child)
		{
			m_PendingDetach.AddLast(child);
		}

        protected virtual void DoDetach(Graph2D child)
        {
            Debug.Assert(child.Parent == this);

            child.Parent = null;

            if (child.IsAbove)
                m_ChildrenGraphAbove.Remove(child);
            else
                m_ChildrenGraphBelow.Remove(child);
        }

		protected void DetachPendings()
		{
			foreach (Graph2D pending in m_PendingDetach)
			{
				// TODO: this is somehow wrong, what if it is reattached to something else during pending?
				if (pending.Parent == this)
					DoDetach(pending);
			}
			m_PendingDetach.Clear();
		}

        public virtual void DetachFromParent()
        {
            if (Parent != null)
                Parent.Detach(this);
        }
    }
}
